
#include "type.h"
#include "value_move_config.h"

#ifndef VALUE_MOVE_NUM_MAX
#error "VALUE_MOVE_NUM_MAX NOT HAVE A CONFIG VALUE"
#endif

typedef struct {
	volatile uint16_t current_value;
	volatile uint16_t target_value;
	volatile uint16_t interval_value;
	volatile uint16_t interval_ticks;
	volatile uint16_t interval_tick_counter;
} SIM_TIMER_STRUCT;

static volatile SIM_TIMER_STRUCT VALUE_MOVES[VALUE_MOVE_NUM_MAX];

void value_move_init(void)
{
	uint8_t i;
	for (i = 0; i < VALUE_MOVE_NUM_MAX; i++) {
		VALUE_MOVES[i].current_value = 0;
		VALUE_MOVES[i].target_value = 0;
		VALUE_MOVES[i].interval_value = 0;
		VALUE_MOVES[i].interval_ticks = 0;
		VALUE_MOVES[i].interval_tick_counter = 0;
	}
}

void* value_move_get_handle(uint8_t value_move_num)
{
	return (void*)(&VALUE_MOVES[value_move_num]);
}

void value_move_stop_move(uint8_t value_move_num)
{
	VALUE_MOVES[value_move_num].target_value = VALUE_MOVES[value_move_num].current_value;
}

void value_move_init_current_value(uint8_t value_move_num, uint16_t set_current_value)
{
	VALUE_MOVES[value_move_num].target_value = set_current_value;
	VALUE_MOVES[value_move_num].current_value = set_current_value;
}

bool_t value_move_check_active(uint8_t value_move_num)
{
	if(VALUE_MOVES[value_move_num].current_value == VALUE_MOVES[value_move_num].target_value){
		return false;
	}
	else{
		return true;
	}
}

void compute_interval_value_and_interval_tick(uint16_t* interval_value, uint16_t* interval_ticks,
												uint16_t totle_value, uint16_t totle_ticks)
{
	if((totle_value == 0)||(totle_ticks == 0)){
		return;
	}
	if(totle_value > totle_ticks){
		*interval_value = totle_value/totle_ticks;
		*interval_ticks = 1;
	}
	else{
		*interval_ticks = totle_ticks/totle_value;
		*interval_value = 1;
	}
}

//move_ticks: how many ticks will take to move "current_value" to "target_value"
void value_move_to_value_by_tick(uint8_t value_move_num, uint16_t set_target_value, uint16_t move_ticks)
{
	uint16_t totle_value = 0;

	value_move_stop_move(value_move_num);

	if(VALUE_MOVES[value_move_num].current_value == set_target_value){
		return;
	}
	if(move_ticks > 0){
		if(VALUE_MOVES[value_move_num].current_value > set_target_value){
			totle_value = VALUE_MOVES[value_move_num].current_value - set_target_value;
		}
		else if(VALUE_MOVES[value_move_num].current_value < set_target_value){
			totle_value = set_target_value - VALUE_MOVES[value_move_num].current_value;
		}
		compute_interval_value_and_interval_tick(&(VALUE_MOVES[value_move_num].interval_value), &(VALUE_MOVES[value_move_num].interval_ticks),
													totle_value, move_ticks);
		VALUE_MOVES[value_move_num].target_value = set_target_value;
		VALUE_MOVES[value_move_num].interval_tick_counter = 0;
	}
	else{
		VALUE_MOVES[value_move_num].interval_value = 0;
		VALUE_MOVES[value_move_num].interval_ticks = 0;
		VALUE_MOVES[value_move_num].target_value = set_target_value;
		VALUE_MOVES[value_move_num].interval_tick_counter = 0;

		VALUE_MOVES[value_move_num].current_value = set_target_value;
		value_move_value_changed_event(value_move_num, VALUE_MOVES[value_move_num].current_value);
	}
}

//rate: how many value pre tick
void value_move_to_value_by_rate(uint8_t value_move_num, uint16_t set_target_value, uint16_t rate)
{
	value_move_stop_move(value_move_num);

	if(VALUE_MOVES[value_move_num].current_value == set_target_value){
		return;
	}
	if(rate > 0){
		if(VALUE_MOVES[value_move_num].current_value > set_target_value){
			if(rate > (VALUE_MOVES[value_move_num].current_value - set_target_value)){
				rate = VALUE_MOVES[value_move_num].current_value - set_target_value;
			}
		}
		else if(VALUE_MOVES[value_move_num].current_value < set_target_value){
			if(rate > (set_target_value - VALUE_MOVES[value_move_num].current_value)){
				rate = set_target_value - VALUE_MOVES[value_move_num].current_value;
			}
		}

		VALUE_MOVES[value_move_num].interval_value = rate;
		VALUE_MOVES[value_move_num].interval_ticks = 1;
		VALUE_MOVES[value_move_num].target_value = set_target_value;
		VALUE_MOVES[value_move_num].interval_tick_counter = 0;
	}
}



void value_move_tick_handler(void)
{
	uint8_t i;
	for (i = 0; i < VALUE_MOVE_NUM_MAX; i++) {
		if(value_move_check_active(i) == 0){
			continue;
		}
		if(VALUE_MOVES[i].interval_value == 0){
			value_move_stop_move(i);
			continue;
		}
		if(VALUE_MOVES[i].interval_ticks == 0){
			value_move_stop_move(i);
			continue;
		}

		VALUE_MOVES[i].interval_tick_counter++;
		if(VALUE_MOVES[i].interval_tick_counter < VALUE_MOVES[i].interval_ticks){
			continue;
		}
		else{
			VALUE_MOVES[i].interval_tick_counter = 0;
		}

		if(VALUE_MOVES[i].current_value > VALUE_MOVES[i].target_value){
			if(VALUE_MOVES[i].current_value - VALUE_MOVES[i].target_value > VALUE_MOVES[i].interval_value){
				VALUE_MOVES[i].current_value -= VALUE_MOVES[i].interval_value;
			}
			else{
				VALUE_MOVES[i].current_value = VALUE_MOVES[i].target_value;
			}
			value_move_value_changed_event(i, VALUE_MOVES[i].current_value);
		}
		else if(VALUE_MOVES[i].current_value < VALUE_MOVES[i].target_value){
			if(VALUE_MOVES[i].target_value - VALUE_MOVES[i].current_value > VALUE_MOVES[i].interval_value){
				VALUE_MOVES[i].current_value += VALUE_MOVES[i].interval_value;
			}
			else{
				VALUE_MOVES[i].current_value = VALUE_MOVES[i].target_value;
			}
			value_move_value_changed_event(i, VALUE_MOVES[i].current_value);
		}
	}
}